package com.example.demo.SecurityConfig;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class UrlAccessDecisionManager implements AccessDecisionManager
{
    @Override
    public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException
    {
        Collection<GrantedAuthority> authorities = (Collection<GrantedAuthority>) authentication.getAuthorities();
        Set<String> userAuthorities = new HashSet<>();
        Set<String> requiredAuthorities = new HashSet<>();
        Iterator<GrantedAuthority> authorityIterator = authorities.iterator();
        while (authorityIterator.hasNext())
        {
            userAuthorities.add(authorityIterator.next().getAuthority());
        }
        authorityIterator.remove();
        Iterator<ConfigAttribute> attributeIterator = collection.iterator();
        while (attributeIterator.hasNext())
        {
            requiredAuthorities.add(attributeIterator.next().getAttribute());
        }
        attributeIterator.remove();
        Iterator<String> iterator = requiredAuthorities.iterator();
        while (iterator.hasNext())
        {
            if (!userAuthorities.contains(iterator.next()))
            {
                throw new AccessDeniedException("Insufficient authority.");
            }
        }
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute)
    {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass)
    {
        return true;
    }
}
